/* 
 * File:   Number.cpp
 * Author: Gab'z
 * 
 * Created on 29 mai 2012, 12:25
 */

#include "Number.h"
#include "Complex.h"
#include "SimpleNumber.h"

namespace calculator {

    Number::Number() : Constant() {
    }

    Number::~Number() {
    }

    Number* add(const Number* n1, const Number* n2) throw (ArithmeticException) {
        const Complex* p_complex1 = dynamic_cast<const Complex*> (n1);
        const Complex* p_complex2 = dynamic_cast<const Complex*> (n2);
        const SimpleNumber* p_nbr1 = dynamic_cast<const SimpleNumber*> (n1);
        const SimpleNumber* p_nbr2 = dynamic_cast<const SimpleNumber*> (n2);
        try {
            if (p_complex1 != 0) {
                if (p_complex2 != 0) return new Complex(*p_complex1 + *p_complex2);
                else if (p_nbr2 != 0) return new Complex(*p_complex1 + *p_nbr2);
            } else if (p_nbr1 != 0) {
                if (p_complex2 != 0) return new Complex(*p_nbr1 + *p_complex2);
                else if (p_nbr2 != 0) return add(p_nbr1, p_nbr2);
            } else if (p_nbr1 != 0 && p_nbr2 != 0) return add(p_nbr1, p_nbr2);
        } catch (ArithmeticException& e) {
            throw;
        }
        throw ArithmeticException("Number addition error");
    }

    Number* sub(const Number* n1, const Number* n2) throw (ArithmeticException) {
        const Complex* p_complex1 = dynamic_cast<const Complex*> (n1);
        const Complex* p_complex2 = dynamic_cast<const Complex*> (n2);
        const SimpleNumber* p_nbr1 = dynamic_cast<const SimpleNumber*> (n1);
        const SimpleNumber* p_nbr2 = dynamic_cast<const SimpleNumber*> (n2);
        try {
            if (p_complex1 != 0) {
                if (p_complex2 != 0) return new Complex(*p_complex1 - *p_complex2);
                else if (p_nbr2 != 0) return new Complex(*p_complex1 - *p_nbr2);
            } else if (p_nbr1 != 0) {
                if (p_complex2 != 0) return new Complex(*p_nbr1 - *p_complex2);
                else if (p_nbr2 != 0) return sub(p_nbr1, p_nbr2);
            }
        } catch (ArithmeticException& e) {
            throw;
        }
        throw ArithmeticException("Number substraction error");
    }

    Number* mul(const Number* n1, const Number* n2) throw (ArithmeticException) {
        const Complex* p_complex1 = dynamic_cast<const Complex*> (n1);
        const Complex* p_complex2 = dynamic_cast<const Complex*> (n2);
        const SimpleNumber* p_nbr1 = dynamic_cast<const SimpleNumber*> (n1);
        const SimpleNumber* p_nbr2 = dynamic_cast<const SimpleNumber*> (n2);
        try {
            if (p_complex1 != 0) {
                if (p_complex2 != 0) return new Complex(*p_complex1 * *p_complex2);
                else if (p_nbr2 != 0) return new Complex(*p_complex1 * *p_nbr2);
            } else if (p_nbr1 != 0) {
                if (p_complex2 != 0) return new Complex(*p_nbr1 * *p_complex2);
                else if (p_nbr2 != 0) return mul(p_nbr1, p_nbr2);
            }
        } catch (ArithmeticException& e) {
            throw;
        }
        throw ArithmeticException("Number multiplication error");
    }

    Number* div(const Number* n1, const Number* n2) throw (ArithmeticException) {
        const Complex* p_complex1 = dynamic_cast<const Complex*> (n1);
        const Complex* p_complex2 = dynamic_cast<const Complex*> (n2);
        const SimpleNumber* p_nbr1 = dynamic_cast<const SimpleNumber*> (n1);
        const SimpleNumber* p_nbr2 = dynamic_cast<const SimpleNumber*> (n2);
        try {
            if (p_complex1 != 0) {
                if (p_complex2 != 0) return new Complex(*p_complex1 / *p_complex2);
                else if (p_nbr2 != 0) return new Complex(*p_complex1 / *p_nbr2);
            } else if (p_nbr1 != 0) {
                if (p_complex2 != 0) return new Complex(*p_nbr1 / *p_complex2);
                else if (p_nbr2 != 0) return div(p_nbr1, p_nbr2);
            }
        } catch (ArithmeticException& e) {
            throw;
        }
        throw ArithmeticException("Number division error");
    }

    Number* pow(const Number* n1, const Number* n2) throw (ArithmeticException) {
        const Complex* p_complex1 = dynamic_cast<const Complex*> (n1);
        const SimpleNumber* p_nbr1 = dynamic_cast<const SimpleNumber*> (n1);
        const SimpleNumber* sn2 = dynamic_cast<const SimpleNumber*> (n2);
        if (sn2 == 0) throw ArithmeticException("Complex power forbidden");
        try {

            if (p_complex1 != 0) {
                Complex c = Complex(*p_complex1);
                c.pow(*sn2);
                return new Complex(c);

            } else if (p_nbr1 != 0) return pow(p_nbr1, sn2);
        } catch (ArithmeticException& e) {
            throw;
        }
        throw ArithmeticException("Number power error");
    }
}
